package com.kun.video.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.kun.video.AbstractApplication;
import com.kun.video.context.ContextService;
import com.kun.video.exception.BizException;
import com.kun.video.thread.ComThreadPool;
import com.kun.video.ui.dialog.message.PopupMessage;
import com.kun.video.util.ComUtil;
import com.kun.video.util.CommandExecutor;
import com.kun.video.util.FFmpegParser;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.image.PixelBuffer;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.media.MediaRef;
import uk.co.caprica.vlcj.player.base.MediaApi;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.embedded.videosurface.CallbackVideoSurface;
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurfaceAdapters;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormat;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormatCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.RenderCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.format.RV32BufferFormat;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.function.Consumer;

/**
 * TODO
 *
 * @author gzc
 * @since 2025/5/25
 **/
public class Vlcj {
    private static final Logger log = LoggerFactory.getLogger(Vlcj.class);
    /**
     * 视频渲染容器
     */
    private MediaPlayerFactory mediaPlayerFactory;
    private EmbeddedMediaPlayer embeddedMediaPlayer;
    public File currVideoFile;
    public long videoDuration;


    private Consumer<FFmpegParser> loadCallback;
    private Runnable stopCallback;
    private Runnable playCallback;
    private Runnable seekCallback;
    private Consumer<FFmpegParser> resetCallback;
    private Consumer<Long> renderCallback;

    public void setLoadCallback(Consumer<FFmpegParser> loadCallback) {
        this.loadCallback = loadCallback;
    }

    public void setStopCallback(Runnable stopCallback) {
        this.stopCallback = stopCallback;
    }

    public void setPlayCallback(Runnable playCallback) {
        this.playCallback = playCallback;
    }

    public void setSeekCallback(Runnable seekCallback) {
        this.seekCallback = seekCallback;
    }

    public void setResetCallback(Consumer<FFmpegParser> resetCallback) {
        this.resetCallback = resetCallback;
    }

    public void setRenderCallback(Consumer<Long> renderCallback) {
        this.renderCallback = renderCallback;
    }

    /**
     * 添加媒体状态监听器
     */
    private final MediaPlayerEventAdapter mediaPlayerEventAdapter = new MediaPlayerEventAdapter() {
        @Override
        public void mediaChanged(MediaPlayer mediaPlayer, MediaRef media) {
//            ComUtil.uiThreadRun(() -> initMediaInfo());
        }

        @Override
        public void opening(MediaPlayer mediaPlayer) {
//            ComUtil.uiThreadRun(() -> timeLabel.setText("加载中..."));
        }
    };
    /**
     * 视频解析参数
     */
    private FFmpegParser fFmpegParser;
    /**
     * 像素缓冲区
     */
    private PixelBuffer<ByteBuffer> videoPixelBuffer;
    public final SimpleObjectProperty<WritableImage> imageProperty = new SimpleObjectProperty<>();

    private ComThreadPool comThreadPool;

    private boolean loading = false;

    public Vlcj() {
        // 初始化VLCJ播放器工厂
        mediaPlayerFactory = new MediaPlayerFactory();
        embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
        // 配置视频渲染表面
        embeddedMediaPlayer.videoSurface().set(new CustomerCallbackVideoSurface());
        comThreadPool = ContextService.getBean(ComThreadPool.class);
    }

    /**
     * 设置媒体源并开始播放
     *
     * @param videoPath 媒体文件路径（支持本地路径/网络流）
     * @throws IllegalArgumentException 当路径无效时抛出异常
     */
    public void loadMedia(String videoPath) {
        // 停止当前播放
        stopMedia();
        if (StrUtil.isBlank(videoPath)) {
            throw new BizException("媒体路径不能为空");
        }
        if (!FileUtil.exist(videoPath)) {
            throw new BizException("视频文件不存在");
        }
        File file = new File(videoPath);
        if (!file.isFile()) {
            throw new BizException("媒体路径不是视频文件");
        }
        this.currVideoFile = file;
        // 异步加载播放器
        comThreadPool.runAsync(() -> {
            try {
                this.fFmpegParser = null;
                // 解析视频
                CommandExecutor.CommandResult result = CommandExecutor.executeCommand("ffmpeg", "-i", videoPath);
                this.fFmpegParser = new FFmpegParser(result.getOutputStr());
                // 配置播放参数
                String[] options = {
                        ":rtsp-tcp",                // 强制RTSP使用TCP传输
                        ":avcodec-hw=any",          // 启用硬件解码
                        ":network-caching=300",     // 网络缓存300ms
                        ":file-caching=1000",       // 文件缓存1s
                        ":live-caching=300"        // 直播流缓存
                };
                System.out.println(fFmpegParser.getDurationMillis());
                this.videoDuration = fFmpegParser.getDurationMillis();
                embeddedMediaPlayer.media().prepare(videoPath, options);
                playMedia();
                initMediaInfo();
                new PopupMessage().success("播放视频" + videoPath, 1000);
            } catch (Exception e) {
                log.error("媒体播放失败: " + e.getMessage(), e);
                new PopupMessage().error("媒体播放失败: " + e.getMessage(), 3000);
                return;
            }
            if (loadCallback != null) {
                loadCallback.accept(this.fFmpegParser);
            }
        });
    }

    public void playMedia() {
        if (embeddedMediaPlayer.controls() != null) {
            embeddedMediaPlayer.controls().play();
        }
        if (playCallback != null) {
            playCallback.run();
        }
    }


    public void stopMedia() {
        if (embeddedMediaPlayer.controls() != null) {
            // 清空页面
            embeddedMediaPlayer.controls().pause();
        }
        if (stopCallback != null) {
            stopCallback.run();
        }
    }

    public void seekMedia(Integer increment) {
//        float seekPosition;
//        if (increment == null) {
//            seekPosition = BigDecimal.valueOf(playProgressSlider.getValue())
//                    .divide(BigDecimal.valueOf(videoDuration), 10, RoundingMode.HALF_UP).floatValue();
//        } else {
//            seekPosition = BigDecimal.valueOf(playProgressSlider.getValue() + increment)
//                    .divide(BigDecimal.valueOf(videoDuration), 10, RoundingMode.HALF_UP).floatValue();
//        }
//        embeddedMediaPlayer.controls().setPosition(seekPosition);
    }

    public void resetMedia() {
        if (embeddedMediaPlayer.controls() != null) {
            embeddedMediaPlayer.controls().pause();
            embeddedMediaPlayer.controls().stop();
        }
        if (resetCallback != null) {
            resetCallback.accept(this.fFmpegParser);
        }
    }

    /**
     * 关闭资源
     */
    public void dispose() {
        embeddedMediaPlayer.events().removeMediaPlayerEventListener(mediaPlayerEventAdapter);
        if (embeddedMediaPlayer != null) {
            embeddedMediaPlayer.release();
        }
        if (mediaPlayerFactory != null) {
            mediaPlayerFactory.release();
        }
    }

    public boolean isPlaying() {
        return embeddedMediaPlayer.status() != null && embeddedMediaPlayer.status().isPlaying();
    }

    /**
     * 初始化媒体元数据
     */
    private void initMediaInfo() {
        try {
            MediaApi media = embeddedMediaPlayer.media();
            if (media == null || media.info() == null) {
                return;
            }
            // 触发解析
            embeddedMediaPlayer.media().parsing().parse();
//            AbstractApplication.getAppStage().setTitle(currVideoFile.getAbsolutePath());
            // 在加载媒体后，显式触发解析
            // 获取视频轨道信息
            String titleStr = currVideoFile.getAbsolutePath();
            if (fFmpegParser != null) {
                String resolution = StrUtil.format("{} x {}", fFmpegParser.getWidth(), fFmpegParser.getHeight());
                titleStr = currVideoFile.getAbsolutePath() +
                        " 分辨率: " + resolution +
                        " 帧率: " + fFmpegParser.getFps() +
                        " 时长: " + fFmpegParser.getDuration();
            }
            AbstractApplication.setStageTitle(titleStr);
        } catch (Exception e) {
            throw new BizException("初始化媒体信息失败", e);
        }
    }

    /**
     * 获取当前播放时间（秒）
     *
     * @return 当前播放的秒数（未开始播放或异常时返回0）
     */
    public long getCurrPlayTime() {
        return embeddedMediaPlayer != null ?
                embeddedMediaPlayer.status().time() : 0L;
    }

    /**
     * 视频表面适配器，桥接VLCJ与JavaFX
     */
    private class CustomerCallbackVideoSurface extends CallbackVideoSurface {
        CustomerCallbackVideoSurface() {
            super(new CustomerBufferFormatCallback(),
                    new CustomerRenderCallback(),
                    true,
                    VideoSurfaceAdapters.getVideoSurfaceAdapter());
        }
    }

    /**
     * 缓冲区格式回调，处理视频尺寸变化
     */
    private class CustomerBufferFormatCallback implements BufferFormatCallback {
        private int sourceWidth;
        private int sourceHeight;

        @Override
        public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) {
            this.sourceWidth = sourceWidth;
            this.sourceHeight = sourceHeight;
            return new RV32BufferFormat(sourceWidth, sourceHeight);
        }

        @Override
        public void allocatedBuffers(ByteBuffer[] buffers) {
            // 验证缓冲区大小：width * height * 4 bytes（32位色深）
            assert buffers[0].capacity() == sourceWidth * sourceHeight * 4;
            // 创建JavaFX像素缓冲区
            PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteBgraPreInstance();
            videoPixelBuffer = new PixelBuffer<>(sourceWidth, sourceHeight, buffers[0], pixelFormat);
            // 更新图像视图
            ComUtil.uiThreadRun(() -> {
                imageProperty.set(new WritableImage(videoPixelBuffer));
            });
        }
    }

    /**
     * 渲染回调，处理帧刷新
     */
    private class CustomerRenderCallback implements RenderCallback {
        @Override
        public void display(MediaPlayer mediaPlayer, ByteBuffer[] nativeBuffers, BufferFormat bufferFormat) {
            // 在JavaFX线程更新像素缓冲区
            ComUtil.uiThreadRun(() -> {
                if (videoPixelBuffer != null) {
                    // 触发缓冲区更新事件
                    videoPixelBuffer.updateBuffer(pb -> null);
                }
                if (renderCallback != null) {
                    renderCallback.accept(mediaPlayer.status().time());
                }
            });
        }
    }
}
